這篇文章是筆者最近在看文章時看到cache在使用上會遇到的一些問題,是自己過去沒有特別思考過的,覺得很特別就把它整理及記錄下來。
why use cache?
通常在系統中會使用cache主要的目的是,減少DB的負擔及加速前端可以更快地拿到資料,這樣聽起來是不是把所有的資料都往裡頭塞就好了? 當然不是,因為cache本身是很吃記憶體的做法,也因為此原因,我們通常把前端最常會和後端拿且不常改動的的資料放在裡面,以利前端可以快速取得.實際上在決定cache要開多大又是另一門學問了,可以放到其他篇講解,或是參考這篇。 如何規劃cache
從上述的內容看起來,只要確定自己的哪些資料要放在cache哪些不要放就沒事了? 實務上並不是這麼回事的,以下就來說明,資料庫可能會被打爆的情境。
常見問題及解法
- 快取雪崩 Cache Avalanche
原因:在各個前端請求發送到後端時,剛好有許多Cache過期了,導致很多請求直接被打到資料庫,造成一個類似雪崩的現象,導致DB被打爆。
解法1(Expiry with different TTL(Time To Live)):對於各個Cache的過期時間進行完善的規劃,也就是不要讓Cache在同個時間點過期,至於多久要過期,就取決於該資料實際上需要的更新頻率。
解法2(Mutex (Locking)):在cache做一個lock的動作,也就是當多個請求併發時,只有一個請求可以跟DB做互動,取完資料後再把結果放到cache中,讓其他請求對cache取資料,如此一來,就不會有很多請求直入DB的問題發生了。
- 快取擊穿 Hotspot Invalid
原因:這個跟雪崩有點類似,也是前端請求發到後端時有Cache過期,不同的點是,這邊是特別指某"一個"請求量極大的Cache過期,導致所有的請求都擊穿了cache直入DB,導致DB被打爆。
解法1:這種Hotspot的請求,在過期的時間設定上,最好就是直接讓他是Hotspot的請求時,不要過期就不會發生了。或是真的確定這個東西沒有要使用了再把它清掉,例如:雙十一節慶的某個商品特賣,可能就會成為一個Hotspot的請求,在雙十一促銷後,平台下架了,這個商品也可以在cache中過期。
解法2(Mutex (Locking)):同快取雪崩的解法2。
- 快取穿透 Cache Penetration
原因:前端發送了很多在redis及db都不存在的select,例如:我的user的id是使用流水號並且是從1開始編號,但前端一定要我查id為0或是-1的資料,在這樣的情況下,我的cache找不到資料,在資料庫也找不到資料.但只要前端發送一次,我的cache跟db都要做一次查詢,穿透了Cache直入DB層,導致DB被打爆。
解法1(observe access pattern):把原先的搜尋規則,在後端的應用層增加判斷的規則,讓在還沒進到時就知道,有些搜尋條件,可以直接回傳對應(錯誤)的訊息,在建立規則後可能需要加上時間驗證,在針對一些特殊(當初沒考慮到)的情況去進行處理,可以避免cache和DB被跟後端之間的互動。
解法2(bloom filter):可以靠布隆過濾器(Bloom Filter),這邊也補充說明一下常見的cache redis本身是可以使用布隆過濾器的,來記錄哪些key是存在的,如果key存在就去cache拿,如果cache拿不到會去找DB拿,如果沒有key的話直接回對應(錯誤)的訊息。
懶人包小總結
- 快取雪崩:資料在DB,但因為大量cache過期,導致DB被打爆。
- 快取擊穿:資料在DB,但因為單個hotspot cache過期,導致DB被打爆。
- 快取穿透:資料不在cache也不在DB,但又要存取,導致DB被打爆。
以上是高併發請求發送時,後端可能會遇到的問題,以上提供的解法為筆者的淺見,或許還有其他更好的解法,可以再參考其他後端大神的文章。若以上內容有誤,煩請各位讀者用力指正,謝謝。